package com.vcredit.creditcat.service.wallet;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.vcredit.bird.enumtype.BankEnum;
import com.vcredit.creditcat.dto.wallet.WalletAmtInOutItemDto;
import com.vcredit.creditcat.dto.wallet.WalletAmtInOutLogDto;
import com.vcredit.creditcat.dto.wallet.WalletDrawHandlerResultDto;
import com.vcredit.creditcat.dto.wallet.WalletDrawInputDto;
import com.vcredit.creditcat.dto.wallet.WalletDrawLogDto;
import com.vcredit.creditcat.dto.wallet.WalletIndexDto;
import com.vcredit.creditcat.model.CustCard;
import com.vcredit.creditcat.model.WalletAmt;
import com.vcredit.creditcat.model.WalletAmtLog;
import com.vcredit.creditcat.model.ext.WalletLogExt;
import com.vcredit.creditcat.service.CustCardService;
import com.vcredit.creditcat.util.ConcurrentDateUtil;
import com.vcredit.creditcat.util.Utility;
import com.vcredit.framework.annotation.Log;
import com.vcredit.framework.exception.BaseException;
import com.vcredit.framework.util.BeanUtil;
import com.vcredit.framework.util.JacksonUtil;

@Service
public class MyWalletService {

	private static final Logger LOG = LoggerFactory
			.getLogger(MyWalletService.class);

	private static final String WALLETAMTLOG_TITLE_A = "提现到{bank}（尾号 {lastno}）";
	private static final String WALLETAMTLOG_TITLE_B = "贷款返现";
	private static final String WALLETAMTLOG_TITLE_C = "办卡返现";

	private static final String BANK_REGEX = "{bank}";
	private static final String NO_REGEX = "{lastno}";

	private static final String SUC_RESULT = "成功";
	private static final String FAIL_RESULT = "失败";
	
	private static final String EXT_NAME = ".txt";
	private static final String ERROR = "error";
	private static final String SEPARATE_LINE = "****************";

	@Autowired
	private WalletAmtService walletAmtService;

	@Autowired
	private WalletAmtLogService walletAmtLogService;

	@Autowired
	private CustCardService custCardService;

	/**
	 * 我的钱包首页
	 * 
	 * @author zhaoqi01
	 * @param cust
	 * @return
	 * @throws Exception
	 */
	@Log
	public WalletIndexDto index(Long custId) throws Exception {
		try {
			List<WalletAmt> custWalletAmts = walletAmtService
					.find(new WalletAmt(custId, null, null, null));
			// 没有余额返回
			if (Utility.isNullOrEmpty(custWalletAmts))
				return new WalletIndexDto(0L, 0);

			WalletAmt custWalletAmt = custWalletAmts.get(0);

			// 查询用户所有提现记录
			List<WalletAmtLog> walletAmtDrawLogs = walletAmtLogService
					.find(new WalletAmtLog(custId, 2, null, null, null, null,
							null));

			// 从未提现过，只要有余额就可以提现
			if (Utility.isNullOrEmpty(walletAmtDrawLogs))
				return new WalletIndexDto(custWalletAmt.getAmt(), 1);

			Date firstDate = ConcurrentDateUtil.getCurrentMonthFirstDate();// 本月第一天时间
			Date lastDate = ConcurrentDateUtil.getCurrentMonthLastDate(); // 本月最后一天时间
			for (WalletAmtLog walletAmtLog : walletAmtDrawLogs) {
				Date drawTime = walletAmtLog.getCreateTime(); // 提现时间
				if (drawTime.after(firstDate) && drawTime.before(lastDate)) {
					return new WalletIndexDto(custWalletAmt.getAmt(), 0);
				}
			}
			return new WalletIndexDto(custWalletAmt.getAmt(), 1);
		} catch (Exception e) {
			LOG.error("------------我的钱包首页出错!! custId : " + custId, e);
			throw e;
		}
	}

	/**
	 * 提现
	 * 
	 * @author zhaoqi01
	 * @param param
	 * @param custId
	 * @throws Exception
	 */
	@Log
	@Transactional(propagation = Propagation.REQUIRED)
	public void drawAmt(WalletDrawInputDto param, Long custId) throws Exception {
		try {
			// 查看钱包
			WalletIndexDto walletIndexDto = this.index(custId);
			// 查询银行卡信息
			CustCard custCard = custCardService.findById(param.getBindCardId());
			if (null != custCard
					&& custCard.getCustId().longValue() == custId.longValue()
					&& custCard.getCardType() == 1
					&& walletIndexDto.getLimitQty() > 0
					&& param.getTakeAmount() <= walletIndexDto.getBalance()) {
				// 扣除钱包中的余额
				WalletAmt custWalletAmt = walletAmtService.find(
						new WalletAmt(custId, null, null, null)).get(0);
				custWalletAmt.setAmt(custWalletAmt.getAmt()
						- param.getTakeAmount());
				walletAmtService.update(custWalletAmt);

				// 新增提现记录,状态为提取中
				walletAmtLogService.insert(new WalletAmtLog(custId, 2, param
						.getTakeAmount(), custCard.getCardId(), 2, null, null));
				return;
			}
			throw new BaseException("钱包余额提现提交参数不正确!");
		} catch (Exception e) {
			LOG.error(
					"------------钱包余额提现出错!!  param = "
							+ JacksonUtil.Obj2Json(param) + "custId = "
							+ custId, e);
			throw e;
		}
	}

	/**
	 * 钱包余额更改历史
	 * 
	 * @author zhaoqi01
	 * @param custId
	 * @return
	 */
	@Log
	public WalletAmtInOutLogDto walletAmtHisTory(Long custId) {
		// 查询余额历史
		List<WalletAmtLog> walletAmtLogList = walletAmtLogService
				.findByCustIdOrderDesc(custId);
		if (Utility.isNullOrEmpty(walletAmtLogList)) {
			return new WalletAmtInOutLogDto(
					new ArrayList<WalletAmtInOutItemDto>());
		}

		List<WalletAmtInOutItemDto> walletAmtInOutItemDtos = new ArrayList<WalletAmtInOutItemDto>();
		for (WalletAmtLog walletAmtLog : walletAmtLogList) {
			if (walletAmtLog.getType() == 2 && walletAmtLog.getStatus() == 2)
				continue; // 排除提现状态为提现中的记录
			walletAmtInOutItemDtos.add(this
					.getWalletAmtInOutItemDto(walletAmtLog));
		}
		return new WalletAmtInOutLogDto(walletAmtInOutItemDtos);
	}

	@Log
	private WalletAmtInOutItemDto getWalletAmtInOutItemDto(
			WalletAmtLog walletAmtLog) {
		if (walletAmtLog.getType() == 2) { // 提现
			// 查询提现到的银行卡信息
			CustCard custCard = custCardService.find(
					new CustCard(walletAmtLog.getBindCardId(), null, null,
							null, null, null, null, null, null, null)).get(0);
			String nameRegex = WALLETAMTLOG_TITLE_A;
			String bankname = this.findBankEnumByCode(custCard.getBankCode())
					.getDesc();
			String cardNo = custCard.getAccountNo();
			String last4CardNo = cardNo.substring(cardNo.length() - 4); // 卡号后四位

			String title = nameRegex.replace(BANK_REGEX, bankname).replace(
					NO_REGEX, last4CardNo);
			String result = walletAmtLog.getStatus() == 1 ? SUC_RESULT
					: FAIL_RESULT;
			return new WalletAmtInOutItemDto(title, walletAmtLog.getType(),
					walletAmtLog.getAmt(), result, walletAmtLog.getCreateTime());
		} else { // 领取收益
			String title = walletAmtLog.getType() == 0 ? WALLETAMTLOG_TITLE_C
					: WALLETAMTLOG_TITLE_B;
			return new WalletAmtInOutItemDto(title, walletAmtLog.getType(),
					walletAmtLog.getAmt(), SUC_RESULT,
					walletAmtLog.getCreateTime());
		}
	}

	/**
	 * 根据bankcode来匹配对应的枚举
	 * 
	 * @author zhaoqi01
	 * @param code
	 * @return
	 */
	public BankEnum findBankEnumByCode(String code) {
		for (BankEnum bankEnum : BankEnum.values()) {
			if (bankEnum.getCode().equals(code)) {
				return bankEnum;
			}
		}
		return null;
	}

	/**
	 * 处理上传的提现结果
	 * 
	 * @author zhaoqi01
	 * @param param
	 * @return
	 */
	@Log
	public WalletDrawHandlerResultDto handlerUploadFile(
			Map<String, String> param) {
		String filePath = param.get("filePath");
		File file = new File(filePath);
		if (!file.exists()) {
			return new WalletDrawHandlerResultDto(0, "文件不存在!", null);
		}
		BufferedReader br = null;
		BufferedWriter bw = null;
		try {
			List<String> errContent = new ArrayList<String>();
			String content = null;
			br = new BufferedReader(new FileReader(file));
			while ((content = br.readLine()) != null) {
				try {
					String[] split = content.split(",");
					Long logId = Long.parseLong(split[0].trim());
					Integer result = Integer.parseInt(split[1].trim());
					if (logId < 0 || (result != 0 && result != 1)) {
						throw new BaseException("钱包提现结果单行数据有误!");
					}
					
					this.handlerWalletDrawResult(logId,result);
				} catch (Exception e) {
					errContent.add(content);
					LOG.error("------------钱包提现定结果处理出错!!", e);
				}
			}

			if (errContent.size() > 0) {
				String errFilePath = filePath.substring(0,filePath.indexOf(EXT_NAME)) + ERROR + EXT_NAME;
				bw = new BufferedWriter(new FileWriter(new File(errFilePath), true));
				bw.write(SEPARATE_LINE);
				bw.newLine();
				bw.flush();
				for (String str : errContent) {
					bw.write(str);
					bw.newLine();
					bw.flush();
				}
				return new WalletDrawHandlerResultDto(2,"上传文件数据处理异常!",errFilePath);
			}
		} catch (Exception e) {
			LOG.error("------------钱包提现定结果处理出错!!",e);
			return new WalletDrawHandlerResultDto(0,"上传文件数据处理异常!",null);
		} finally {
			if (null != br) {
				try {
					br.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (null != bw) {
				try {
					bw.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

		return new WalletDrawHandlerResultDto(1,"上传文件数据处理成功!",null);
	}

	@Log
	@Transactional(propagation = Propagation.REQUIRED)
	private void handlerWalletDrawResult(Long logId, Integer result) throws BaseException {
		// 根据id查询对应提现记录
		WalletAmtLog walletAmtLog = walletAmtLogService.findById(logId);
		if(null == walletAmtLog) {
			throw new BaseException("没有找到对应的提现记录!! logId=" + logId + ", result=" + result);
		}
		
		if(walletAmtLog.getStatus() != 2) {
			throw new BaseException("对应的提现记录状态不为提现中!! logId=" + logId + ", result=" + result);
		}
		
		// 查询钱包
		WalletAmt walletAmt = new WalletAmt(walletAmtLog.getCustId(), null, null, null);
		walletAmt = walletAmtService.find(walletAmt).get(0);
		
		// 如果提现失败，需要将提现金额返还给钱包余额
		if(result == 0) {
			walletAmt.setAmt(walletAmt.getAmt() + walletAmtLog.getAmt());
			walletAmtService.update(walletAmt);
		}
		
		// 修改提现状态
		walletAmtLog.setStatus(result);
		walletAmtLogService.update(walletAmtLog);
	}

	/**
	 * 条件查询提现记录
	 * @author zhaoqi01
	 * @param param
	 * @return
	 */
	public List<WalletDrawLogDto> queryWalletLog(WalletDrawLogDto param) {
		List<WalletLogExt> walletLogExts = walletAmtLogService.findForWeb(param);
		List<WalletDrawLogDto> dtos = new ArrayList<WalletDrawLogDto>();
		for (WalletLogExt walletLogExt : walletLogExts) {
			WalletDrawLogDto dto = new WalletDrawLogDto();
			BeanUtil.copy(walletLogExt, dto);
			dtos.add(dto);
		}
		return dtos;
	}

	/**
	 * 更新提现状态
	 * @author zhaoqi01
	 * @param param
	 * @return
	 */
	@Log
	@Transactional
	public boolean updateWalletDrawStatus(WalletDrawLogDto param) {
		Long drawId = param.getDrawId();
		Integer status = param.getStatus();
		
		// 根据id查询提现记录
		WalletAmtLog walletAmtLog = walletAmtLogService.findById(drawId);
		Integer oldStatus = walletAmtLog.getStatus();
		Long drawAmt = walletAmtLog.getAmt();
		
		if(null == walletAmtLog || oldStatus.intValue() == status.intValue())
			return false;
		
		// 查询用户钱包
		WalletAmt walletAmt = new WalletAmt(walletAmtLog.getCustId(), null, null, null);
		walletAmt = walletAmtService.find(walletAmt).get(0);
		
		boolean flag = false;
		if(status == 0) {
			
			if(oldStatus == 1 || oldStatus == 2) { // 将成功或提现中改为失败
				// 钱包余额增加
				walletAmt.setAmt(walletAmt.getAmt() + drawAmt);
				flag = updateWalletAmt(walletAmt);
			}
		} 
		
		else if(status == 1) {
			
			if(oldStatus == 0) { // 将失败改为成功
				// 钱包余额减少
				walletAmt.setAmt(walletAmt.getAmt() - drawAmt);
				flag = updateWalletAmt(walletAmt);
			} else if(oldStatus == 2) { // 将提现中改为成功
				// 钱包余额不变
				flag = true;
			}
			
		} 
		
		else {
			
			if(oldStatus == 0) { // 将失败改为提现中
				// 钱包余额减少
				walletAmt.setAmt(walletAmt.getAmt() - drawAmt);
				flag = updateWalletAmt(walletAmt);
			} else if(oldStatus == 1) { // 将成功改为提现中
				// 钱包余额不变
				flag = true;
			}
			
		}
		
		if(!flag) {
			return false;
		}
		// 更新提现日志状态
		walletAmtLog.setStatus(status);
		walletAmtLogService.update(walletAmtLog);
		return true;
	}

	private boolean updateWalletAmt(WalletAmt walletAmt) {
		if(walletAmt.getAmt() < 0) {
			return false;
		}
		walletAmtService.update(walletAmt);
		return true;
	}
}
